//============================================================================
// Name        : Tetragnatha.cpp
// Author      : MC e Baggio
//============================================================================

#include <iostream>
#include <fstream>
#include <queue>
#include <list>
#include <sstream>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/tr1/memory.hpp>

#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

#include <ctime>
#include <cstdlib>

#include "./classes_net/DownloadParser.h"
#include "./classes_net/URL.h"
#include "./classes_dados/ManagerBerthier.h"
#include "./classes_dados/Hasher.h"
#include "./classes_dados/ThreadFunctionDatabase.h"


#include "./classes_dados/URLDiskClass.h"
#include "./classes_outros/Config.h"
#include "./classes_outros/MCSugaException.h"
#include "./classes_outros/TetraRecovery.h"

using namespace std;


void initList(list<URL> &urlList){
	URL tempUrl;
	tempUrl = URL("www.globo.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.terra.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.terra.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.uol.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.ita.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.ufmg.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.aol.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.yahoo.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.cnn.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.bbc.co.uk/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.centraldoslinks.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.sites.jpa.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.guialinks.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.nytimes.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.planetasites.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.abril.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.sitesnobrasil.com/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.mapadaweb.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.top30.com.br/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.mundosites.net/", "", "http://");
	urlList.push_back(tempUrl);
	tempUrl = URL("www.ig.com.br/", "", "http://");
	urlList.push_back(tempUrl);
}



int main(int argc, char *argv[]) {
	
	time_t hoje;
	time(&hoje);
	cout << "Bem-vindo ao Tetragnatha" << endl;
	cout << "Criado por MC e Baggio, antes do dia 5/5/2008" << endl;
	cout << "Jah se passaram " << hoje << " segundos desde 1 de janeiro de 1970" << endl;
	
	curl_global_init(CURL_GLOBAL_DEFAULT);
	
	pthread_attr_t attr;
	size_t stacksize;
	uint numDownloaderThreads = Config::getNumDownloaderThreads();
	uint numQueueThreads = Config::getNumQueueThreads();
	
	pthread_t threads[numDownloaderThreads];
	pthread_t queueThread[numQueueThreads];
	pthread_t robotThreads[100];
	
	list<URL> urlList;
	DownloadParser downloadTeste;
	
	std::tr1::shared_ptr<URLFileDealer> urlFileDealer = URLFileDealer::getInstance();
	std::tr1::shared_ptr<ManagerBerthier> mb = ManagerBerthier::getInstance();

	
	int rc;	
	unsigned int t = 0; //kker valor - MC Suga, caguei
	
	TetraRecovery backup;
	
	bool inicializaFrio = true;
	
//	if (Config::redirectCOutToFile())
//		freopen ("myfile.txt","w",stdout);	
	
	if(argc < 2){
		cout << " Verifique argumentos... " << endl;
		exit(1);
	}
	

	switch(*argv[1]){
		case '0':
//			if (Config::runInitializationScript())
//			system("./setup.sh");
			break;
		case '1':			
			//Recupera apos quebra
			cout << " Modo de recuperacao... " << endl;
			backup.recovery();
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			cout << "      Tetragnatha Recuperado " << endl;
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			inicializaFrio = false;
			break;
			
		case '2':
			//Recupera apos quebra
			cout << "Modo especial: " << endl;
			cout << "Gerando estatisticas: backup.currentState() " << endl;
			time_t tempo;
			time(&tempo);
			freopen ("./out_logger/niveis","a",stdout);
			while(true) backup.currentState(tempo);  // fica gerando estatistica
			return 0;
			break;
		case '3':
			cout << "Modo especial: " << endl;
			cout << "Gerando estatisticas: backup.contaPaginasDisco() "<< endl;
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			backup.contaPaginasDisco();
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			return 0;
			break;
		case '4':
			cout << "Modo especial: " << endl;
			cout << "Limpa URLs repetidas dos discos ... " << endl;
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			backup.cleanDisk();
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			return 0;
			break;
		case '5':
			cout << "Modo especial: " << endl;
			cout << "Cria arquivo de Hash ... " << endl;
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			backup.createHashFile();
			cout << "-----------------------------------------------------------" << endl;
			cout << "-----------------------------------------------------------" << endl;
			return 0;
			break;
			
		default:
			cout << " Verifique argumentos... " << endl;	
			exit(1);
	}
	
	if(inicializaFrio){
		//Carrega lista de URLs
		initList(urlList);
		
		int numUrlsNaMain = 0;
		list<URL>::iterator it;
		
		for(it = urlList.begin(); it != urlList.end(); it++){
			list<URL> urlListTemp;
			downloadTeste.setURL(it->toString());
			urlListTemp = downloadTeste.getNewURLs();
			urlFileDealer->addURLs(urlListTemp);
			numUrlsNaMain += urlListTemp.size();
		}		
	}	
	cout << "-----------------------------------------------------------" << endl;
	cout << "-----------------------------------------------------------" << endl;	

	mb->initializeDownloaderQueues(numDownloaderThreads);
	
	time_t timeSyncher;
	void * semFuncao;
 
	time(&timeSyncher);
	ThreadFunctionDatabase::setSyncLifeThread(timeSyncher);
	
	pthread_attr_init(&attr);
	stacksize = Config::getQueueThreadStackSize();
	pthread_attr_setstacksize (&attr, stacksize);

	
	//REENCHEDOR DE FILAS
    for(t=0; t<numQueueThreads; t++){ 
    	//rc = pthread_create(&queueThread[t], NULL, ThreadFunctionDatabase::manageDownloaderQueues, (void *)t);
    	rc = pthread_create(&queueThread[t], &attr, ThreadFunctionDatabase::manageDownloaderQueues, (void *)t); 
    	if (rc){
    	  cout << "ERROR2; return code from pthread_create() is " << rc << "\n";
    	  exit(-1);
      }
   }
    
	pthread_attr_init(&attr);
	stacksize = Config::getRobotsThreadStackSize();
	pthread_attr_setstacksize (&attr, stacksize);
	uint numRobotsThreads = Config::getMaxRobotsThreads();
	
	for(t=0; t<numRobotsThreads; t++){ 
		rc = pthread_create(&robotThreads[t], &attr, ThreadFunctionDatabase::getDomainRobots, (void *)t); 
		if (rc){
		  cout << "ERROR1; return ROBOTS code from pthread_create() is " << rc << "\n";
		  exit(-1);
		}
	}	
    

//--------------------------------------------------------------------------------	
	
    pthread_attr_init(&attr);
    stacksize = Config::getDownloaderThreadStackSize();
    pthread_attr_setstacksize (&attr, stacksize);
    
    //Funcionarios do ManagerBerthier
	   for(t=0; t<numDownloaderThreads; t++){ 
	      rc = pthread_create(&threads[t], &attr, ThreadFunctionDatabase::downloadInit, (void *)t);
	      //rc = pthread_create(&threads[t], NULL, ThreadFunctionDatabase::downloadInit, (void *)t);
	      if (rc){
	    	  cout << "ERROR3; return code from pthread_create() is " << rc << "\n";
	    	  exit(-1);
	      }
	   }
	   

	
	    for(t=0; t<numQueueThreads; t++){ 
		      rc = pthread_join(queueThread[t], &semFuncao);
		      if (rc){
		         printf("ERROR; return code from pthread_join() is %d\n", rc);
		         exit(-1);
		      }
		}
		
	
	  for(t=0; t<numDownloaderThreads; t++){ 
	      rc = pthread_join(threads[t], &semFuncao);
	      if (rc){
	         printf("ERROR2; return code from pthread_join() is %d\n", rc);
	         exit(-1);
	      }
	   }		
	  cout << "***********************************************************" << endl;
	  cout << "*   Tetragnatha desligara em 10 segundos...               *" << endl;
	  cout << "***********************************************************" << endl;
	  
	  sleep(10); 
	  
	  exit(0);
//--------------------------------------------------------------------------------
	  return 0;	
}


